<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FFmpeg 命令生成器</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
    <div class="bg-white p-6 rounded-lg shadow-lg w-full max-w-2xl">
        <h1 class="text-2xl font-bold mb-6 text-center">FFmpeg 命令生成器</h1>
        <div class="space-y-4">
            <div>
                <label for="inputFile" class="block text-sm font-medium text-gray-700">输入文件路径</label>
                <input type="text" id="inputFile" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" placeholder="例如：input.mp4" required>
                <p id="inputFileError" class="text-red-600 text-sm mt-1 hidden">请输入输入文件路径</p>
            </div>
            <div>
                <label for="outputFile" class="block text-sm font-medium text-gray-700">输出文件路径</label>
                <input type="text" id="outputFile" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" placeholder="例如：output.mkv" required>
                <p id="outputFileError" class="text-red-600 text-sm mt-1 hidden">请输入输出文件路径</p>
            </div>
            <div>
                <label for="format" class="block text-sm font-medium text-gray-700">输出格式</label>
                <select id="format" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" onchange="updateEncoderOptions()">
                    <option value="mp4">MP4</option>
                    <option value="mkv">MKV</option>
                    <option value="avi">AVI</option>
                    <option value="mov">MOV</option>
                    <option value="webm">WebM</option>
                </select>
            </div>
            <div>
                <label for="hwaccel" class="block text-sm font-medium text-gray-700">硬件加速 <span class="text-gray-500 text-xs">(GPU 加速解码框架，需匹配解码器)</span></label>
                <select id="hwaccel" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" onchange="updateDecoderOptions(); updateEncoderOptions(); toggleNvencOptions()">
                    <option value="">无 (软件解码)</option>
                    <option value="cuda">NVIDIA CUDA</option>
                    <option value="qsv">Intel QSV</option>
                    <option value="amf">AMD AMF</option>
                    <option value="videotoolbox">macOS VideoToolbox</option>
                </select>
            </div>
            <div>
                <label for="decoder" class="block text-sm font-medium text-gray-700">视频解码器 <span class="text-gray-500 text-xs">(解码输入视频，硬件解码需匹配硬件加速)</span></label>
                <select id="decoder" class="mt-1 block w-full p-2 border border-gray-300 rounded-md">
                    <option value="">默认 (自动，推荐)</option>
                    <option value="h264">H.264 (软件解码)</option>
                    <option value="hevc">H.265/HEVC (软件解码)</option>
                    <option value="vp9">VP9 (软件解码)</option>
                    <option value="h264_cuvid" data-hwaccel="cuda">H.264 (NVIDIA CUVID, 需 -hwaccel cuda)</option>
                    <option value="hevc_cuvid" data-hwaccel="cuda">H.265/HEVC (NVIDIA CUVID, 需 -hwaccel cuda)</option>
                    <option value="h264_qsv" data-hwaccel="qsv">H.264 (Intel QSV, 需 -hwaccel qsv)</option>
                    <option value="hevc_qsv" data-hwaccel="qsv">H.265/HEVC (Intel QSV, 需 -hwaccel qsv)</option>
                    <option value="h264_videotoolbox" data-hwaccel="videotoolbox">H.264 (macOS VideoToolbox, 需 -hwaccel videotoolbox)</option>
                    <option value="hevc_videotoolbox" data-hwaccel="videotoolbox">H.265/HEVC (macOS VideoToolbox, 需 -hwaccel videotoolbox)</option>
                </select>
            </div>
            <div>
                <label for="encoder" class="block text-sm font-medium text-gray-700">视频编码器 <span class="text-gray-500 text-xs">(编码输出视频，需匹配输出格式及硬件加速)</span></label>
                <select id="encoder" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" onchange="toggleNvencOptions()">
                    <option value="copy">复制视频流 (保持原格式)</option>
                    <option value="libx264">H.264 (libx264, 软件编码)</option>
                    <option value="libx265">H.265/HEVC (libx265, 软件编码)</option>
                    <option value="libvpx-vp9">VP9 (libvpx-vp9, 软件编码)</option>
                    <option value="h264_nvenc">H.264 (NVIDIA NVENC, 需 NVIDIA GPU)</option>
                    <option value="hevc_nvenc">H.265/HEVC (NVIDIA NVENC, 需 NVIDIA GPU)</option>
                    <option value="h264_qsv">H.264 (Intel QSV, 需 Intel QSV)</option>
                    <option value="hevc_qsv">H.265/HEVC (Intel QSV, 需 Intel QSV)</option>
                    <option value="h264_amf">H.264 (AMD AMF, 需 AMD GPU)</option>
                    <option value="hevc_amf">H.265/HEVC (AMD AMF, 需 AMD GPU)</option>
                    <option value="h264_videotoolbox">H.264 (macOS VideoToolbox, 需 macOS)</option>
                    <option value="hevc_videotoolbox">H.265/HEVC (macOS VideoToolbox, 需 macOS)</option>
                </select>
            </div>
            <div>
                <label for="audioEncoder" class="block text-sm font-medium text-gray-700">音频编码器 <span class="text-gray-500 text-xs">(编码输出音频，推荐 AAC)</span></label>
                <select id="audioEncoder" class="mt-1 block w-full p-2 border border-gray-300 rounded-md">
                    <option value="copy">复制音频流 (保持原格式)</option>
                    <option value="aac">AAC (广泛兼容)</option>
                    <option value="mp3">MP3</option>
                    <option value="flac">FLAC (无损)</option>
                </select>
            </div>
            <div>
                <label for="bitrate" class="block text-sm font-medium text-gray-700">视频码率 (kbps，可选) <span class="text-gray-500 text-xs">(留空使用恒定质量模式 -cq)</span></label>
                <input type="number" id="bitrate" class="mt-1 block w-full p-2 border border-gray-300 rounded-md" placeholder="例如：5000">
            </div>
            <div id="nvencOptions" class="hidden">
                <label for="preset" class="block text-sm font-medium text-gray-700">编码预设 <span class="text-gray-500 text-xs">(p1 最快，p7 最高质量)</span></label>
                <select id="preset" class="mt-1 block w-full p-2 border border-gray-300 rounded-md">
                    <option value="p1">p1 (最快)</option>
                    <option value="p2">p2</option>
                    <option value="p3">p3</option>
                    <option value="p4">p4</option>
                    <option value="p5">p5</option>
                    <option value="p6" selected>p6</option>
                    <option value="p7">p7 (最高质量)</option>
                </select>
                <p class="text-gray-600 text-sm mt-1 bg-gray-100 p-2 rounded-md">
                    编码预设控制编码速度和压缩效率：<br>
                    - p1（最快）：编码速度快，压缩率低，文件较大。<br>
                    - p7（最高质量）：编码速度慢，压缩率高，文件较小。<br>
                    推荐 p6，平衡速度和压缩率。
                </p>
            </div>
            <div id="nvencCqOptions" class="hidden">
                <label for="cq" class="block text-sm font-medium text-gray-700">恒定质量 (CQ) <span class="text-gray-500 text-xs">(18-28，值越小质量越高)</span></label>
                <select id="cq" class="mt-1 block w-full p-2 border border-gray-300 rounded-md">
                    <option value="18">18 (最高质量)</option>
                    <option value="19">19</option>
                    <option value="20">20</option>
                    <option value="21">21</option>
                    <option value="22">22</option>
                    <option value="23" selected>23</option>
                    <option value="24">24</option>
                    <option value="25">25</option>
                    <option value="26">26</option>
                    <option value="27">27</option>
                    <option value="28">28 (最低质量)</option>
                </select>
                <p class="text-gray-600 text-sm mt-1 bg-gray-100 p-2 rounded-md">
                    恒定质量 (CQ) 控制视频质量和文件大小：<br>
                    - 18（最高质量）：文件最大，质量最好。<br>
                    - 28（最低质量）：文件最小，质量较低。<br>
                    推荐 23，平衡质量和文件大小。<br>
                    <strong>与预设的关系</strong>：慢预设（如 p7）提高压缩率，配合低 CQ（如 18）可获得高质量但文件仍较小；快预设（如 p1）配合高 CQ（如 28）可能导致文件过大或质量下降。
                </p>
            </div>
            <button onclick="generateCommand()" class="w-full bg-blue-600 text-white p-2 rounded-md hover:bg-blue-700">生成 FFmpeg 命令</button>
            <div id="output" class="mt-4 p-4 bg-gray-50 border border-gray-200 rounded-md hidden">
                <p class="font-semibold mb-2">生成的 FFmpeg 命令：</p>
                <div class="relative">
                    <pre id="command" class="text-sm text-gray-800 bg-white border border-gray-300 rounded-md p-2 h-24 overflow-y-auto"></pre>
                    <button onclick="copyCommand()" class="absolute top-2 right-2 bg-green-600 text-white px-3 py-1 rounded-md hover:bg-green-700 text-sm">复制命令</button>
                </div>
                <p id="copyFeedback" class="text-green-600 text-sm mt-2 hidden">命令已复制到剪贴板！</p>
            </div>
        </div>
    </div>

    <script>
        // 编码器与输出格式的兼容性映射
        const encoderCompatibility = {
            mp4: ['copy', 'libx264', 'libx265', 'h264_nvenc', 'hevc_nvenc', 'h264_qsv', 'hevc_qsv', 'h264_amf', 'hevc_amf', 'h264_videotoolbox', 'hevc_videotoolbox'],
            mkv: ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_nvenc', 'hevc_nvenc', 'h264_qsv', 'hevc_qsv', 'h264_amf', 'hevc_amf', 'h264_videotoolbox', 'hevc_videotoolbox'],
            avi: ['copy', 'libx264', 'h264_nvenc', 'h264_qsv', 'h264_amf', 'h264_videotoolbox'],
            mov: ['copy', 'libx264', 'libx265', 'h264_nvenc', 'hevc_nvenc', 'h264_qsv', 'hevc_qsv', 'h264_amf', 'hevc_amf', 'h264_videotoolbox', 'hevc_videotoolbox'],
            webm: ['copy', 'libvpx-vp9']
        };

        // 编码器与硬件加速的兼容性映射
        const encoderHwaccelCompatibility = {
            cuda: ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_nvenc', 'hevc_nvenc'],
            qsv: ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_qsv', 'hevc_qsv'],
            amf: ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_amf', 'hevc_amf'],
            videotoolbox: ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_videotoolbox', 'hevc_videotoolbox'],
            '': ['copy', 'libx264', 'libx265', 'libvpx-vp9', 'h264_nvenc', 'hevc_nvenc', 'h264_qsv', 'hevc_qsv', 'h264_amf', 'hevc_amf', 'h264_videotoolbox', 'hevc_videotoolbox']
        };

        // 支持 -cq 的编码器
        const cqSupportedEncoders = ['h264_nvenc', 'hevc_nvenc'];

        // 所有编码器选项
        const encoderOptions = [
            { value: 'copy', text: '复制视频流 (保持原格式)' },
            { value: 'libx264', text: 'H.264 (libx264, 软件编码)' },
            { value: 'libx265', text: 'H.265/HEVC (libx265, 软件编码)' },
            { value: 'libvpx-vp9', text: 'VP9 (libvpx-vp9, 软件编码)' },
            { value: 'h264_nvenc', text: 'H.264 (NVIDIA NVENC, 需 NVIDIA GPU)', hwaccel: 'cuda' },
            { value: 'hevc_nvenc', text: 'H.265/HEVC (NVIDIA NVENC, 需 NVIDIA GPU)', hwaccel: 'cuda' },
            { value: 'h264_qsv', text: 'H.264 (Intel QSV, 需 Intel QSV)', hwaccel: 'qsv' },
            { value: 'hevc_qsv', text: 'H.265/HEVC (Intel QSV, 需 Intel QSV)', hwaccel: 'qsv' },
            { value: 'h264_amf', text: 'H.264 (AMD AMF, 需 AMD GPU)', hwaccel: 'amf' },
            { value: 'hevc_amf', text: 'H.265/HEVC (AMD AMF, 需 AMD GPU)', hwaccel: 'amf' },
            { value: 'h264_videotoolbox', text: 'H.264 (macOS VideoToolbox, 需 macOS)', hwaccel: 'videotoolbox' },
            { value: 'hevc_videotoolbox', text: 'H.265/HEVC (macOS VideoToolbox, 需 macOS)', hwaccel: 'videotoolbox' }
        ];

        // 所有解码器选项
        const decoderOptions = [
            { value: '', text: '默认 (自动，推荐)' },
            { value: 'h264', text: 'H.264 (软件解码)' },
            { value: 'hevc', text: 'H.265/HEVC (软件解码)' },
            { value: 'vp9', text: 'VP9 (软件解码)' },
            { value: 'h264_cuvid', text: 'H.264 (NVIDIA CUVID, 需 -hwaccel cuda)', hwaccel: 'cuda' },
            { value: 'hevc_cuvid', text: 'H.265/HEVC (NVIDIA CUVID, 需 -hwaccel cuda)', hwaccel: 'cuda' },
            { value: 'h264_qsv', text: 'H.264 (Intel QSV, 需 -hwaccel qsv)', hwaccel: 'qsv' },
            { value: 'hevc_qsv', text: 'H.265/HEVC (Intel QSV, 需 -hwaccel qsv)', hwaccel: 'qsv' },
            { value: 'h264_videotoolbox', text: 'H.264 (macOS VideoToolbox, 需 -hwaccel videotoolbox)', hwaccel: 'videotoolbox' },
            { value: 'hevc_videotoolbox', text: 'H.265/HEVC (macOS VideoToolbox, 需 -hwaccel videotoolbox)', hwaccel: 'videotoolbox' }
        ];

        // 更新编码器选项
        function updateEncoderOptions() {
            const format = document.getElementById('format').value;
            const hwaccel = document.getElementById('hwaccel').value;
            const encoderSelect = document.getElementById('encoder');
            const selectedEncoder = encoderSelect.value || 'copy';

            // 清空当前编码器选项
            encoderSelect.innerHTML = '';

            // 确定兼容的编码器
            const compatibleEncoders = encoderCompatibility[format].filter(encoder =>
                encoderHwaccelCompatibility[hwaccel].includes(encoder)
            );

            // 确保至少包含 copy 选项
            if (!compatibleEncoders.includes('copy')) {
                compatibleEncoders.push('copy');
            }

            // 添加兼容的编码器选项
            encoderOptions.forEach(option => {
                if (compatibleEncoders.includes(option.value)) {
                    const opt = document.createElement('option');
                    opt.value = option.value;
                    opt.textContent = option.text;
                    if (option.value === selectedEncoder) {
                        opt.selected = true;
                    }
                    if (option.hwaccel && option.hwaccel !== hwaccel && hwaccel !== '') {
                        opt.disabled = true;
                    }
                    encoderSelect.appendChild(opt);
                }
            });

            console.log('Updated encoder options:', compatibleEncoders);
            toggleNvencOptions();
        }

        // 更新解码器选项
        function updateDecoderOptions() {
            const hwaccel = document.getElementById('hwaccel').value;
            const decoderSelect = document.getElementById('decoder');
            const selectedDecoder = decoderSelect.value;

            // 清空当前解码器选项
            decoderSelect.innerHTML = '';

            // 添加所有解码器选项
            decoderOptions.forEach(option => {
                const opt = document.createElement('option');
                opt.value = option.value;
                opt.textContent = option.text;
                if (option.value === selectedDecoder) {
                    opt.selected = true;
                }
                if (hwaccel && option.hwaccel && option.hwaccel !== hwaccel) {
                    opt.disabled = true;
                }
                decoderSelect.appendChild(opt);
            });

            console.log('Updated decoder options');
        }

        // 切换 NVENC 选项（-preset 和 -cq）的显示
        function toggleNvencOptions() {
            const encoder = document.getElementById('encoder').value;
            const nvencOptions = document.getElementById('nvencOptions');
            const nvencCqOptions = document.getElementById('nvencCqOptions');
            if (cqSupportedEncoders.includes(encoder)) {
                nvencOptions.classList.remove('hidden');
                nvencCqOptions.classList.remove('hidden');
            } else {
                nvencOptions.classList.add('hidden');
                nvencCqOptions.classList.add('hidden');
            }
        }

        // 复制命令到剪贴板
        function copyCommand() {
            const commandText = document.getElementById('command').textContent;
            navigator.clipboard.writeText(commandText).then(() => {
                const copyFeedback = document.getElementById('copyFeedback');
                copyFeedback.classList.remove('hidden');
                setTimeout(() => {
                    copyFeedback.classList.add('hidden');
                }, 2000);
            }).catch(err => {
                alert('复制失败，请手动复制命令：' + err);
            });
        }

        // 生成 FFmpeg 命令
        function generateCommand() {
            console.log('generateCommand called');
            const inputFile = document.getElementById('inputFile').value.trim();
            const outputFile = document.getElementById('outputFile').value.trim();
            const format = document.getElementById('format').value;
            const hwaccel = document.getElementById('hwaccel').value;
            const encoder = document.getElementById('encoder').value;
            const decoder = document.getElementById('decoder').value;
            const audioEncoder = document.getElementById('audioEncoder').value;
            const bitrate = document.getElementById('bitrate').value.trim();
            const preset = document.getElementById('preset').value;
            const cq = document.getElementById('cq').value;

            // 重置错误提示
            document.getElementById('inputFileError').classList.add('hidden');
            document.getElementById('outputFileError').classList.add('hidden');

            // 验证输入文件和输出文件
            let hasError = false;
            if (!inputFile) {
                document.getElementById('inputFileError').classList.remove('hidden');
                hasError = true;
            }
            if (!outputFile) {
                document.getElementById('outputFileError').classList.remove('hidden');
                hasError = true;
            }
            if (hasError) {
                return;
            }

            // 验证硬件加速和解码器兼容性
            const selectedDecoderOption = decoderOptions.find(opt => opt.value === decoder);
            if (hwaccel && selectedDecoderOption && selectedDecoderOption.hwaccel && selectedDecoderOption.hwaccel !== hwaccel) {
                alert(`错误：解码器 ${selectedDecoderOption.text} 需要 -hwaccel ${selectedDecoderOption.hwaccel}，而不是 -hwaccel ${hwaccel}。`);
                return;
            }

            // 验证硬件加速和编码器兼容性
            const selectedEncoderOption = encoderOptions.find(opt => opt.value === encoder);
            if (hwaccel && selectedEncoderOption && selectedEncoderOption.hwaccel && selectedEncoderOption.hwaccel !== hwaccel) {
                alert(`警告：编码器 ${selectedEncoderOption.text} 需要 ${selectedEncoderOption.hwaccel} 硬件支持，而您选择了 -hwaccel ${hwaccel}，可能不兼容。请确认您的硬件支持。`);
            }

            let command = 'ffmpeg';
            if (hwaccel) {
                command += ` -hwaccel ${hwaccel}`;
            }
            if (decoder) {
                command += ` -c:v ${decoder}`;
            }
            command += ` -i "${inputFile}"`;
            command += ` -c:v ${encoder}`;

            // 处理码率或恒定质量模式
            if (bitrate) {
                command += ` -b:v ${bitrate}k`;
            } else if (cqSupportedEncoders.includes(encoder)) {
                command += ` -preset ${preset} -cq ${cq}`;
            }

            if (audioEncoder) {
                command += ` -c:a ${audioEncoder}`;
            }
            command += ` -f ${format} "${outputFile}"`;

            const outputDiv = document.getElementById('output');
            const commandPre = document.getElementById('command');
            commandPre.textContent = command;
            outputDiv.classList.remove('hidden');
            console.log('Command generated:', command);
        }

        // 初始化编码器、解码器和 NVENC 选项
        updateEncoderOptions();
        updateDecoderOptions();
        toggleNvencOptions();
    </script>
</body>
</html>